#include "motor_encoder.h"
#include "timer.h"

static pthread_t thread1, thread2;
static pthread_mutex_t encoder_edge_count_mutex = PTHREAD_MUTEX_INITIALIZER;    //保护临界资源encoder_edge_count的互斥体
static int encoder_edge_count = 0;  //编码器输入的边缘计数

//监听GPIO输入边缘的线程，参数为GPIO号
static void *gpio_edge_poll(void *arg)
{
    //用于监听GPIO输入边缘的线程应当屏蔽定时器的SIGALRM信号，让控制线程运行信号处理函数
    mask_sig_alarm();
    //打开GPIO的value文件
    char * file_path = malloc(sizeof(char) * 40);
    sprintf(file_path, "/sys/class/gpio/gpio%d/value", (int) arg);
    int encoder_fd = open(file_path, O_RDONLY);
    free(file_path);
    if (encoder_fd < 0)
    {
        perror("open error");
        exit(0);
    }
    //设置需要监听的事件，对于GPIO的value文件，POLLPRI | POLLERR是监听它的边缘触发事件
    //https://www.kernel.org/doc/Documentation/gpio/gpio-legacy.txt
    struct pollfd pfd;
    pfd.fd = encoder_fd;
    pfd.events = POLLPRI | POLLERR;

    while (1)
    {
        //poll函数会阻塞，直到GPIO输入的边缘触发
        if (poll(&pfd, 1, -1) == -1)
        {
            perror("poll error");
            exit(0);
        }
        //每次边缘触发，编码器输入的边缘计数都加1
        if (pfd.revents & POLLPRI) {
            char buffer[2];
            read(encoder_fd, buffer, sizeof(buffer));
            
            pthread_mutex_lock(&encoder_edge_count_mutex);
            encoder_edge_count++;
            //printf("%d\n", encoder_edge_count);
            pthread_mutex_unlock(&encoder_edge_count_mutex);
        }
    }
    close(encoder_fd);
}

//创建两个实时线程，第一个线程监听GPIO17（编码器的A相输出）的输入边缘，第二个线程监听GPIO27（编码器的B相输出）的输入边缘。
void init_encoder_poll_threads()
{
    encoder_edge_count = 0;
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
    struct sched_param param = {.sched_priority = 99};
    pthread_attr_setschedparam(&attr, &param);
    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);

    pthread_create(&thread1, &attr, gpio_edge_poll, (void *) 17);
    pthread_create(&thread2, &attr, gpio_edge_poll, (void *) 27);

}

//获取并清空编码器输入的边缘计数
int get_and_clear_encoder_edge_count()
{
    int ret;
    pthread_mutex_lock(&encoder_edge_count_mutex);
    ret = encoder_edge_count;
    encoder_edge_count = 0;
    pthread_mutex_unlock(&encoder_edge_count_mutex);
    return ret;
}






